package com.tcs.utils;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;

import com.tcs.tsrm.beans.ClusteringThresholds;

public class PrepareForRanking {
	public static String clusterIndexesPath;
	public static String originalMatrixPath;
	public static String outputPath; // Output/coin-bst/EOT20
	public static String nonTrivialMatrixPath;
	private static HashMap<Integer, Integer> originalToNonTrivial = new HashMap<Integer, Integer>();
	private static int totalSubsequences = 0;
	private static int remainingSubsequences = 0;
	private static int support = 0;

	public void computeNonTrivialSubs(ClusteringThresholds thresholds) {
		try {
			support = thresholds.getSupport();
			HashMap<Integer, ArrayList<Integer>> allClusters = loadClusters();
			HashMap<Integer, ArrayList<Double>> originalMatrix = loadOriginalMatrix();
			HashMap<Integer, ArrayList<Double>> nonTrivialMatrix = loadNonTrivialMatrix();
			HashMap<Integer, ArrayList<Integer>> clustersWithNonTrivialSubs = prepareRanking(
					allClusters, originalMatrix);

			HashMap<Integer, ArrayList<Double>> centroids = getCentroids(
					clustersWithNonTrivialSubs, nonTrivialMatrix);

			printResults(clustersWithNonTrivialSubs, originalMatrix,
					nonTrivialMatrix, centroids);
			printStats(totalSubsequences, remainingSubsequences,thresholds);

		} catch (NumberFormatException e) {
			e.printStackTrace();
		}

	}

	private void printStats(int totalSubs, int remainingSubs,ClusteringThresholds thresholds) {
		if(thresholds.isDebug()==true)
		{
		File fileOriginal = new File(outputPath + "/" + "NonTrivial" + "/"
				+ "SubsStats.txt");
		fileOriginal.getParentFile().mkdirs();
		PrintWriter statOut2;
		try {
			statOut2 = new PrintWriter(new BufferedWriter(new FileWriter(
					fileOriginal, false)));
			statOut2.write("Total subsequences, Remaining Subsequences\n");
			statOut2.write(totalSubs + "," + remainingSubs);
			statOut2.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		}
	}

	private HashMap<Integer, ArrayList<Double>> getCentroids(
			HashMap<Integer, ArrayList<Integer>> clustersWithNonTrivialSubs,
			HashMap<Integer, ArrayList<Double>> nonTrivialMatrix) {
		HashMap<Integer, ArrayList<Double>> centroids = new HashMap<Integer, ArrayList<Double>>();

		for (Integer key : clustersWithNonTrivialSubs.keySet()) {
			ArrayList<Integer> subsIndex = clustersWithNonTrivialSubs.get(key);
			ArrayList<ArrayList<Double>> nonTrivialSubs = new ArrayList<ArrayList<Double>>();
			for (Integer eachIndex : subsIndex) {
				int nonTrivialIndex = originalToNonTrivial.get(eachIndex);
				nonTrivialSubs.add(nonTrivialMatrix.get(nonTrivialIndex));
			}
			ArrayList<Double> centroid = calculateCentroid(nonTrivialSubs);
			centroids.put(key, centroid);
		}

		return centroids;
	}

	private ArrayList<Double> calculateCentroid(
			ArrayList<ArrayList<Double>> nonTrivialSubs) {
		double[] sum = new double[nonTrivialSubs.get(0).size()];
		double noOfPoint = nonTrivialSubs.size();
		for (ArrayList<Double> eachSubs : nonTrivialSubs) {
			for (int i = 0; i < eachSubs.size(); i++) {
				sum[i] += eachSubs.get(i);
			}
		}

		ArrayList<Double> centroid = new ArrayList<Double>();
		for (int i = 0; i < sum.length; i++) {
			centroid.add(sum[i] / noOfPoint);
		}
		return centroid;
	}

	private HashMap<Integer, ArrayList<Double>> loadNonTrivialMatrix()
			throws NumberFormatException {
		HashMap<Integer, ArrayList<Double>> nonTrivialMatrix = new HashMap<Integer, ArrayList<Double>>();
		FileInputStream fstream;
		try {
			fstream = new FileInputStream(nonTrivialMatrixPath);

			DataInputStream in = new DataInputStream(fstream);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String strLine;
			while ((strLine = br.readLine()) != null) {
				String[] data = strLine.split(",");
				double nonTrivialMatIndex = Double.valueOf(data[0]);
				double originalMatIndex = Double.valueOf(data[1]);
				originalToNonTrivial.put((int) originalMatIndex,
						(int) nonTrivialMatIndex);
				ArrayList<Double> aRow = new ArrayList<Double>();
				for (int i = 2; i < data.length; i++) {
					aRow.add(Double.valueOf(data[i]));
				}
				nonTrivialMatrix.put((int) nonTrivialMatIndex, aRow);
			}
			br.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return nonTrivialMatrix;
	}

	private void printResults(
			HashMap<Integer, ArrayList<Integer>> clustersWithNonTrivialSubs,
			HashMap<Integer, ArrayList<Double>> originalMatrix,
			HashMap<Integer, ArrayList<Double>> nonTrivialMatrix,
			HashMap<Integer, ArrayList<Double>> centroids) {
		PrepareForRanking pfr = new PrepareForRanking();
		pfr.printBeforeRanking(clustersWithNonTrivialSubs, originalMatrix,
				outputPath);
	}

	private HashMap<Integer, ArrayList<Integer>> prepareRanking(
			HashMap<Integer, ArrayList<Integer>> allClusters,
			HashMap<Integer, ArrayList<Double>> originalMatrix) {
		HashMap<Integer, ArrayList<Integer>> clusterWithNonTrivialSubs = new HashMap<Integer, ArrayList<Integer>>();
		for (Integer key : allClusters.keySet()) {
			ArrayList<Integer> nonTrivialIndexes = allClusters.get(key);
			clusterWithNonTrivialSubs.put(key, nonTrivialIndexes);
		}
		return clusterWithNonTrivialSubs;
	}

	private HashMap<Integer, ArrayList<Double>> loadOriginalMatrix()
			throws NumberFormatException {
		HashMap<Integer, ArrayList<Double>> originalMatrix = new HashMap<Integer, ArrayList<Double>>();
		FileInputStream fstream;
		try {
			fstream = new FileInputStream(originalMatrixPath);
			DataInputStream in = new DataInputStream(fstream);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String strLine;
			while ((strLine = br.readLine()) != null) {
				String[] data = strLine.split(",");
				double rowId = Double.valueOf(data[0]);
				ArrayList<Double> aRow = new ArrayList<Double>();
				for (int i = 1; i < data.length; i++) {
					aRow.add(Double.valueOf(data[i]));
				}
				originalMatrix.put((int) rowId, aRow);
			}
			br.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return originalMatrix;

	}

	private HashMap<Integer, ArrayList<Integer>> loadClusters()
			throws NumberFormatException {
		HashMap<Integer, ArrayList<Integer>> clusters = new HashMap<Integer, ArrayList<Integer>>();
		FileInputStream fstream;
		try {
			fstream = new FileInputStream(clusterIndexesPath);
			DataInputStream in = new DataInputStream(fstream);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String strLine;
			while ((strLine = br.readLine()) != null) {
				String[] data = strLine.split(",");
				int clusterId = Integer.valueOf(data[0]);
				ArrayList<Integer> aCluster = new ArrayList<Integer>();
				for (int i = 1; i < data.length; i++) {
					aCluster.add(Integer.valueOf(data[i]));
				}
				clusters.put(clusterId, aCluster);
			}
			br.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return clusters;
	}

	public void printBeforeRanking(
			HashMap<Integer, ArrayList<Integer>> clustersWithNonTrivialSubs,
			HashMap<Integer, ArrayList<Double>> originalMatrix,
			String outputPath) {
		for (Integer key : clustersWithNonTrivialSubs.keySet()) {
			ArrayList<Integer> subsIndex = clustersWithNonTrivialSubs.get(key);
			if (subsIndex.size() < support) {
				continue;
			}
			File fileOriginal = new File(outputPath + "/" + "NonTrivial" + "/"
					+ "Motifs-Org-2" + "/" + key + ".txt");
			fileOriginal.getParentFile().mkdirs();
			PrintWriter statOut2;
			try {
				statOut2 = new PrintWriter(new BufferedWriter(new FileWriter(
						fileOriginal, false)));

				for (Integer eachIndex : subsIndex) {
					statOut2.write(eachIndex + ",");
					String subs = makeString(originalMatrix.get(eachIndex));
					statOut2.write(subs);
					statOut2.write("\n");
				}
				statOut2.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

	private String makeString(ArrayList<Double> arrayList) {
		String out = "";
		for (Double d : arrayList) {
			out += d + ",";
		}
		return out;
	}

}
